package com.stone.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.stone.bean.dto.MenuAddDTO;
import com.stone.bean.dto.MenuUpdateDTO;
import com.stone.bean.vo.MenuNodeVO;
import com.stone.config.SpringContextConfig;
import com.stone.config.exception.BusinessException;
import com.stone.constant.Const;
import com.stone.entity.SysMenu;
import com.stone.entity.SysRoleMenu;
import com.stone.mapper.SysMenuMapper;
import com.stone.mapper.SysRoleMenuMapper;
import com.stone.service.SysMenuService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统菜单 服务实现类
 * </p>
 *
 * @author stone
 * @since 2022-04-02
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Resource
    private SysRoleMenuMapper sysRoleMenuMapper;

    @Override
    public List<SysMenu> listByRoleIds(List<Long> roleIdList) {
        if (CollUtil.isEmpty(roleIdList)) {
            return null;
        }
        List<SysRoleMenu> sysRoleMenus = sysRoleMenuMapper.selectList(new QueryWrapper<SysRoleMenu>().in("role_id", roleIdList));
        // 获取到所有的菜单id
        List<Long> menuIds = Lists.newArrayList();
        for (SysRoleMenu sysRoleMenu : sysRoleMenus) {
            menuIds.add(sysRoleMenu.getMenuId());
        }
        if (CollUtil.isEmpty(menuIds)) {
            return null;
        }
        List<SysMenu> list = list(new QueryWrapper<SysMenu>()
                .eq("enable", true)
                .in("id", menuIds)
                .orderByAsc("order_num")
                .orderByDesc("create_time")
        );
        return list;
    }

    @Override
    public void addMenu(MenuAddDTO dto) {
        SysMenu sysMenu = JSON.parseObject(JSON.toJSONString(dto), SysMenu.class);
        sysMenu.setCreateBy(SpringContextConfig.loginUserId(dto.getToken()));
        sysMenu.setCreateTime(LocalDateTime.now());
        if (sysMenu.getOrderNum() < 0) {
            throw new BusinessException("排序不能为负数");
        }
        save(sysMenu);
    }

    @Override
    public void updateMenu(MenuUpdateDTO dto) {
        SysMenu dbMenu = getById(dto.getId());
        if (Objects.isNull(dbMenu)) {
            throw new BusinessException("不存在的数据");
        }
        SysMenu sysMenu = JSON.parseObject(JSON.toJSONString(dto), SysMenu.class);
        sysMenu.setUpdateBy(SpringContextConfig.loginUserId(dto.getToken()));
        sysMenu.setUpdateTime(LocalDateTime.now());
        if (sysMenu.getOrderNum() < 0) {
            throw new BusinessException("排序不能为负数");
        }
        updateById(sysMenu);
    }

    @Override
    public void delMenu(Long menuId, String token) {
        SysMenu dbMenu = getById(menuId);
        if (Objects.isNull(dbMenu)) {
            throw new BusinessException("不存在的数据");
        }
        //判断是否有下级菜单
        int count = count(new QueryWrapper<SysMenu>()
                .eq("parent_id", menuId)
                .eq("enable", true)
        );
        if (count > 0) {
            throw new BusinessException("菜单下存在子菜单，不能删除");
        }
        removeById(menuId);
    }

    @Override
    public void changeEnable(Long menuId, String token) {
        SysMenu dbMenu = getById(menuId);
        if (Objects.isNull(dbMenu)) {
            throw new BusinessException("不存在的数据");
        }
        SysMenu sysMenu = new SysMenu();
        sysMenu.setId(menuId);
        sysMenu.setEnable(!dbMenu.getEnable());
        sysMenu.setUpdateBy(SpringContextConfig.loginUserId(token));
        sysMenu.setUpdateTime(LocalDateTime.now());
        updateById(sysMenu);
    }

    @Override
    public List<MenuNodeVO> selectTreeAll() {
        List<SysMenu> sysMenuList = list(new QueryWrapper<SysMenu>()
                .orderByAsc("order_num")
                .orderByDesc("create_time")
                .eq("enable", true)
        );
        //拼接菜单树
        List<MenuNodeVO> list = buildTreeVoWithResList(sysMenuList);
        return list;
    }

    /**
     * 构造字母层级
     */
    private List<MenuNodeVO> buildTreeVoWithResList(List<SysMenu> sysMenuList) {
        if (CollUtil.isEmpty(sysMenuList)) {
            return null;
        }
        List<SysMenu> catalogueList = sysMenuList.stream().filter(sysMenu -> Const.Menu.catalogue.type.equals(sysMenu.getType())).collect(Collectors.toList());
        if (CollUtil.isEmpty(catalogueList)) {
            return null;
        }
        catalogueList.sort(Comparator.comparing(SysMenu::getOrderNum));
        // 目录
        List<MenuNodeVO> result = new ArrayList<>(catalogueList.size());
        for (SysMenu sysMenu : catalogueList) {
            MenuNodeVO vo = new MenuNodeVO();
            BeanUtils.copyProperties(sysMenu, vo);
            result.add(vo);
        }
        // 菜单
        List<SysMenu> menuList = sysMenuList.stream().filter(sysMenu -> Const.Menu.menu.type.equals(sysMenu.getType())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(menuList)) {
            for (SysMenu sysMenu : menuList) {
                for (MenuNodeVO parentVO : result) {
                    if (parentVO.getId().equals(sysMenu.getParentId())) {
                        MenuNodeVO vo = new MenuNodeVO();
                        BeanUtils.copyProperties(sysMenu, vo);
                        parentVO.getChildren().add(vo);
                        break;
                    }
                }
            }
            for (MenuNodeVO vo : result) {
                vo.getChildren().sort(Comparator.comparing(MenuNodeVO::getOrderNum));
                List<Long> collect = vo.getChildren().stream().map(MenuNodeVO::getId).collect(Collectors.toList());
                vo.setChildrenIds(collect);
            }
        }
        // 按钮
        List<SysMenu> buttonList = sysMenuList.stream().filter(sysMenu -> Const.Menu.button.type.equals(sysMenu.getType())).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(buttonList)) {
            for (SysMenu sysMenu : buttonList) {
                for (MenuNodeVO parentVO : result) {
                    if (parentVO.getChildrenIds().contains(sysMenu.getParentId())) {
                        List<MenuNodeVO> menuVOList = parentVO.getChildren();
                        for (MenuNodeVO menuVO : menuVOList) {
                            if (menuVO.getId().equals(sysMenu.getParentId())) {
                                MenuNodeVO vo = new MenuNodeVO();
                                BeanUtils.copyProperties(sysMenu, vo);
                                menuVO.getChildren().add(vo);
                                break;
                            }
                        }
                        break;
                    }
                }
            }
        }
        return result;
    }
}
